/**
 * 项目名：	Rumba Plan
 * 
 * 版权所有(C)，上海海鼎信息工程股份有限公司，2007，所有权利保留。
 * 
 * 文件名：	RB_v20r01.java
 * 模块说明：	
 * 修改历史：
 * Apr 26, 2007 - zhangyanbo - 创建。
 */
package com.hd123.rumba.upgrade.v20.r02;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import net.sf.hibernate.Hibernate;
import net.sf.hibernate.HibernateException;
import net.sf.hibernate.Session;
import net.sf.hibernate.Transaction;

import org.apache.log4j.Logger;

import com.hd123.rumba.action.qt.ViewQuery;
import com.hd123.rumba.cartridge.CartRumba;
import com.hd123.rumba.cartridge.FVRumbaQt;
import com.hd123.rumba.cartridge.biz.BCFVReference;
import com.hd123.rumba.cartridge.biz.BCartFunctionView;
import com.hd123.rumba.domain.IDomain;
import com.hd123.rumba.domain.IDomainFuncView;
import com.hd123.rumba.domain.IDomainMgr;
import com.hd123.rumba.exception.BusinessException;
import com.hd123.rumba.qt.def.IQueryDef;
import com.hd123.rumba.qt.def.IQueryDefinitionMgr;
import com.hd123.rumba.qt.result.QueryResultDescription;
import com.hd123.rumba.runtime.HibernateSession;
import com.hd123.rumba.runtime.NamingMgr;
import com.hd123.rumba.runtime.OperateContext;
import com.hd123.rumba.upgrade.DBCommand;
import com.hd123.rumba.upgrade.Upgrade;
import com.hd123.rumba.user.IPermission;
import com.hd123.rumba.user.IPermissionMgr;
import com.hd123.rumba.user.IUserMgr;
import com.hd123.rumba.util.Version;

/**
 * @author zhangyanbo
 * 
 */
public class RB_v20r01 extends Upgrade {

  public RB_v20r01() throws Exception {
    super();
    baseVersion = new Version("2.0.1.0");
    targetVersion = new Version("2.0.2.0");
    cartUuid = this.getCart(CartRumba.class).getUuid();
    logger = Logger.getLogger(this.getClass());
  }

  @Override
  public void executeDdl() throws BusinessException {
    DBCommand cmd = new DBCommand();
    execFile(cmd, "upgrade.sql");
    this.upg_9609(cmd);
  }

  @Override
  public void executeData() throws BusinessException {
    logger.info("升级" + this.getCart(CartRumba.class).getCaption());
    try {
      initPermissions();
    } catch (HibernateException e) {
      throw new BusinessException(e);
    }
  }

  private IDomainMgr domainMgr = null;
  private IUserMgr userMgr = null;

  private IDomainMgr getDomainMgr() throws BusinessException {
    if (domainMgr == null)
      domainMgr = (IDomainMgr) NamingMgr.getInstance().lookupMgr(IDomainMgr.class);
    return domainMgr;
  }

  private IUserMgr getUserMgr() throws BusinessException {
    if (userMgr == null)
      userMgr = (IUserMgr) NamingMgr.getInstance().lookupMgr(IUserMgr.class);
    return userMgr;
  }

  /*
   * ===== 以下为任务单[9609]升级处理。 =====
   */

  /** 升级DomainFuncView。 */
  private void upg_9609(DBCommand cmd) throws BusinessException {
    execFile(cmd, "upg_9609_step1.sql");
    try {
      List<IDomain> domains = getAllDomains(cmd.getSession());
      for (IDomain domain : domains) {
        logger.info("[upg_9609] domain: " + domain.getNameCode() + " ...");
        List<IDomainFuncView> dfvs = getDFVsByDomain(cmd.getSession(), domain);
        sortDFVs(dfvs);
        updateDFVsT(cmd.getSession(), dfvs);
      }
    } catch (HibernateException e) {
      throw new BusinessException(e);
    }
    execFile(cmd, "upg_9609_step2.sql");
  }

  /** 取得所有的域。 */
  private List<IDomain> getAllDomains(Session ses) throws BusinessException, HibernateException {
    List list = ses.find("from " + IDomain.class.getName() + " d");
    return (List<IDomain>) list;
  }

  /** 取得指定域的所有IDomainFuncView */
  private List<IDomainFuncView> getDFVsByDomain(Session ses, IDomain domain)
      throws BusinessException, HibernateException {
    List list = ses.find("from " + IDomainFuncView.class.getName() + " dfv"
        + " where dfv.domain.uuid = ? order by dfv.loadOrder", domain.getUuid(), Hibernate.STRING);
    return (List<IDomainFuncView>) list;
  }

  /** 将dfvs按照CFV的依赖关系进行排序 */
  private void sortDFVs(List<IDomainFuncView> dfvs) throws BusinessException {
    // 查找所有相关的BCartFunctionView
    List<BCartFunctionView> bcfvs = new ArrayList();
    for (IDomainFuncView dfv : dfvs) {
      String cfvUuid = dfv.getFuncView().getUuid();
      BCartFunctionView bcfv = getCartMgr().getFunctionView(cfvUuid);
      bcfvs.add(bcfv);
    }
    // 遍历每一条依赖关系，并调整dfvs顺序
    for (BCartFunctionView bcfv : bcfvs) {
      int itemIdx = indexOfDFVs(dfvs, bcfv.getUuid());
      if (itemIdx < 0)
        continue;
      for (BCFVReference cfvRef : bcfv.getReferences()) {
        String cfvUuid = this.getCartMgr().getFunctionViewByPrefix(cfvRef.getRefCFVPrefix())
            .getUuid();
        int refIdx = indexOfDFVs(dfvs, cfvUuid);
        if (refIdx < 0)
          continue;
        if (refIdx > itemIdx)
          moveBeforeDFVs(dfvs, refIdx, itemIdx);
      }
    }
  }

  /** 取得指定CFV在dfvs中的位置 */
  private int indexOfDFVs(List<IDomainFuncView> dfvs, String cfvUuid) throws BusinessException {
    int index = -1;
    for (IDomainFuncView dfv : dfvs)
      if (cfvUuid.equals(dfv.getFuncView().getUuid())) {
        index = dfvs.indexOf(dfv);
        break;
      }
    return index;
  }

  /** 在dfvs中将itemIdx所指定位置的元素移动到destIdx指定位置。 */
  private void moveBeforeDFVs(List<IDomainFuncView> dfvs, int itemIdx, int destIdx) {
    assert itemIdx > destIdx;
    IDomainFuncView dfv = dfvs.get(itemIdx);
    dfvs.remove(dfv);
    dfvs.add(destIdx, dfv);
  }

  /** 按照dfvs的顺序作为新的loadOrder，并保存到数据库中。 */
  private void updateDFVsT(Session ses, List<IDomainFuncView> dfvs) throws BusinessException,
      HibernateException {
    OperateContext operate = new OperateContext(getUserMgr().getSysUser());
    Transaction tx = ses.beginTransaction();
    try {
      for (IDomainFuncView dfv : dfvs) {
        int idx = dfvs.indexOf(dfv);
        dfv.setLoadOrder(new Integer(idx));
        getDomainMgr().saveDomainFuncView(dfv, operate);
      }
      tx.commit();
    } catch (BusinessException e) {
      tx.rollback();
      throw e;
    } catch (HibernateException e) {
      tx.rollback();
      throw e;
    } finally {
      ses.flush();
    }
  }

  private void initPermissions() throws HibernateException, BusinessException {
    IQueryDefinitionMgr qdm = (IQueryDefinitionMgr) NamingMgr.getInstance().lookupMgr(
        IQueryDefinitionMgr.class);
    IDomainMgr domainMgr = (IDomainMgr) NamingMgr.getInstance().lookupMgr(IDomainMgr.class);
    IUserMgr userMgr = (IUserMgr) NamingMgr.getInstance().lookupMgr(IUserMgr.class);
    IPermissionMgr permMgr = (IPermissionMgr) NamingMgr.getInstance().lookupMgr(
        IPermissionMgr.class);
    try {
      // 增加打印设计权限
      permMgr.initPermissionsT(ViewQuery.class);

      // 升级IQueryDef
      String prefix = FVRumbaQt.FUNCV_PREFIX + ".查询报表./";
      List perms = HibernateSession.getSession().find(
          "from " + IPermission.class.getName() + " o where o.code like ?", prefix + '%',
          Hibernate.STRING);
      for (int i = 0; i < perms.size(); i++) {
        IPermission perm = (IPermission) perms.get(i);
        String queryName = perm.getCode().substring(prefix.length());
        String location = "";
        String filename = queryName;
        int index = queryName.lastIndexOf("/");
        if (index >= 0) {
          location = queryName.substring(0, index);
          filename = queryName.substring(index + 1);
        }
        IQueryDef queryDef = qdm.getQueryDefByFile(location, filename);
        if (queryDef == null) {
          logger.info("创建查询定义：location=" + location + ", filename=" + filename);
          Transaction tx = HibernateSession.getSession().beginTransaction();
          try {
            queryDef = qdm.createQueryDef(domainMgr.getRootDomain());
            queryDef.setName(filename.replace(".sql", ""));
            queryDef.setLocation(location);
            queryDef.setFilename(filename);
            List<String> cfvUuids = new ArrayList<String>();
            cfvUuids.add(this.getCFV(FVRumbaQt.class).getUuid());
            qdm.saveQueryDef(queryDef, cfvUuids, new OperateContext(userMgr.getSysUser()));
            tx.commit();
          } catch (Exception e) {
            tx.rollback();
            throw e;
          }
        }
      }

      // 升级TQrd
      Iterator qrds = HibernateSession.getSession().iterate(
          "from " + QueryResultDescription.class.getName() + " o where o.qdUuid is null");
      while (qrds.hasNext()) {
        Session sess = HibernateSession.getSession();
        Transaction tx = sess.beginTransaction();
        try {
          QueryResultDescription qrd = (QueryResultDescription) qrds.next();
          qrd.setQueryCriteriaInfo(qrd.getInfo());
          sess.saveOrUpdate(qrd);
          tx.commit();
        } catch (Exception e) {
          tx.rollback();
          throw e;
        }
      }
    } catch (Exception e) {
      if (e instanceof HibernateException)
        throw (HibernateException) e;
      else
        throw new BusinessException(e);
    }
  }

}
